#include"Task.hpp"
#include<string>
#include<vector>
#include<cstdlib>
#include<ctime>
#include<cassert>
#include<unistd.h>
#include<sys/types.h>
#include<sys/wait.h>

const int processnum = 10;
std::vector<task_t> tasks;

class channel
{
public:
    channel(int cmdfd, int slaverid, const std::string& processname)
        :_cmdfd(cmdfd)
        ,_slaverid(slaverid)
        ,_processname(processname)
        {}
public:
    int _cmdfd;
    pid_t _slaverid;
    std::string _processname;
};

void slaver()
{
    while(true)
    {
        int cmdcode = 0;
        int n = read(0, &cmdcode, sizeof(int));
        if(n == sizeof(int))
        {
            std::cout << "slaver say@ get a command: " << getpid() << " : cmdcode: " <<cmdcode <<std::endl;
            if(cmdcode >= 0 && cmdcode < tasks.size())
            {
                tasks[cmdcode]();
            }
            if(n == 0)
            {
                break;
            }
        }
    }
}

void InitProcessPool(std::vector<channel>* channels)
{
    std::vector<int> oldfds;
    for(int i = 0; i < processnum; i++)
    {
        int pipefd[2];
        int n = pipe(pipefd);
        assert(!n);
        (void)n;
        pid_t id = fork();
        if(id == 0)
        {
            std::cout << "child: " << getpid() << " closs history fd: ";
            for(auto fd : oldfds)
            {
                std::cout << fd << " ";
                close(fd);
            }
            std::cout << "\n";
            close(pipefd[1]);
            dup2(pipefd[0], 0);
            close(pipefd[0]);
            slaver();
            std::cout << "process: " << getpid() << " quit" << std::endl;
            exit(0);
        }
        close(pipefd[0]);
        std::string name = "process-" + std::to_string(i);
        channels->push_back(channel(pipefd[1], id, name));
        oldfds.push_back(pipefd[1]);
        sleep(1);
    }
}

void Debug(const std::vector<channel>& channels)
{
    for(const auto &c : channels)
    {
        std::cout << c._cmdfd << " " << c._slaverid << " " << c._processname << std::endl;        
    }
}

void Menu()
{
    std::cout << "###############################################" << std::endl;
    std::cout << "# 1. 刷新日志          2. 刷新出来野怪          #" << std::endl;
    std::cout << "# 3. 检测软件是否更新   4. 更新用的血量和蓝量   #" << std::endl;
    std::cout << "#                      0. 退出                #" << std::endl;
    std::cout << "###############################################" << std::endl;
}

void ctrlSlaver(const std::vector<channel>& channels)
{
    int which = 0;
    while(true)
    {
        int select = 0;
        Menu();
        std::cout << "Please Enter@ ";
        std::cin >> select;
        if(select <= 0 || select >=5)
        {
            break;
        }
        int cmdcode = select - 1;
        std::cout << "father say: " << " cmdcode: " <<
            cmdcode << " already sendto " << channels[which]._slaverid << " process name: "
                << channels[which]._processname << std::endl;
        write(channels[which]._cmdfd, &cmdcode, sizeof(cmdcode));
        which++;
        which %= channels.size();
    }
}

void QuitProcess(const std::vector<channel>& channels)
{
    for(const auto& c : channels)
    {
        close(c._cmdfd);
        waitpid(c._slaverid, nullptr, 0);
    }
}

int main()
{
    LoadTask(&tasks);
    srand(time(nullptr)^getpid()^1023);
    std::vector<channel> channels;
    InitProcessPool(&channels);
    ctrlSlaver(channels);
    QuitProcess(channels);

    return 0;
}